package com.cxx.autoconfigure.serializer;

import cn.hutool.core.util.DesensitizedUtil;
import com.cxx.autoconfigure.annontation.SensitiveField;
import com.cxx.autoconfigure.constant.SensitizeType;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;

import java.io.IOException;

/**
 * 脱敏序列化器，用于在序列化字符串时根据不同的脱敏类型进行数据脱敏。
 * 这里可以使用Object接收序列化值，否则只能序列化特定类型的属性值。
 * 相当于劫持原来的字段值并重新生成新的字段值（可以改变原来字段的数据类型）
 * 这里因为写在了SensitiveField注解上，所以只有带@SensitiveField注解的属性才会进入。
 * 1. 序列化字段先进入到createContextual()实现方法中，且相同的字段只会进入一次
 * 2. 序列化字段值进入到serialize()生成新的值。
 * 3. 依次循环遍历（如果是数组结构类型的数据）
 */
public class SensitizeSerializer extends JsonSerializer<Object> implements ContextualSerializer {

    /**
     * 脱敏类型，默认为DEFAULT
     */
    private SensitizeType type;

    /**
     * 根据上下文信息创建自定义的序列化器，用于处理带有@Sensitize注解的属性。
     *
     * @param prov     序列化器提供者，用于获取其他序列化器
     * @param property 当前属性的信息，用于获取注解和属性类型
     * @return 自定义的序列化器实例
     */
    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) {
        if (property != null) {
            // 获取该注解上的脱敏类型
            SensitiveField annotation = property.getAnnotation(SensitiveField.class);
            if (annotation != null) {
                this.type = annotation.type();
            }
        }

        // 返回默认的序列化器
        return this;
    }

    /**
     * 序列化字符串时调用，根据脱敏类型对字符串进行相应的脱敏处理。
     *
     * @param value       待序列化的字符串
     * @param gen         JSON生成器，用于写入处理后的字符串
     * @param serializers 序列化器提供者，用于获取其他序列化器
     * @throws IOException 如果序列化过程中发生I/O错误
     */
    @Override
    public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        switch (type) {
            case PHONE:
                gen.writeString(DesensitizedUtil.mobilePhone((String) value));
                break;
            case EMAIL:
                gen.writeString(DesensitizedUtil.email((String) value));
                break;
            case ID_CARD:
                gen.writeString(DesensitizedUtil.idCardNum((String) value, 1, 2));
                break;
            case BANK_CARD:
                gen.writeString(DesensitizedUtil.bankCard((String) value));
                break;
            case ADDRESS:
                gen.writeString(DesensitizedUtil.address((String) value, 8));
                break;
            case CHINESE_NAME:
                gen.writeString(DesensitizedUtil.chineseName((String) value));
                break;
            case PASSWORD:
                gen.writeString(DesensitizedUtil.password((String) value));
                break;
            default:
                // 可以重新序列化字段数据类型
                gen.writeString("******");
                break;
        }
    }
}
